package com.handa.documentManager.controller;


import com.handa.common.entity.LoginUser;
import com.handa.common.entity.Response;
import com.handa.common.exception.ServiceException;
import com.handa.common.utils.RequestContext;
import com.handa.documentManager.entity.DTO.*;
import com.handa.documentManager.entity.QTO.SystemFIleQto1;
import com.handa.documentManager.entity.VO.MinioFileInfoVO;
import com.handa.documentManager.entity.VO.UploadResult;
import com.handa.documentManager.service.impl.MinIOFileService;
import com.handa.documentManager.service.impl.MinioFileUploadService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@RestController
@RequestMapping("/documentManager/tokenFile")
@Slf4j
public class MinioFileController {

    @Resource
    private MinIOFileService minIOFileService;

    @Resource
    private MinioFileUploadService minioFileUploadService;
    /**
     * 获取所有BucketName
     */
    @GetMapping("/getBucketList")
    public Response<List<String>> getBucketList() {
        return Response.success(minIOFileService.getAllBucket());
    }

    /**
     * 获取一个Bucket 中 某个文件夹下的所有文件列表
     */
    @GetMapping("/getAllFilesByFolder")
    public Response<List<FileObject>> getAllFilesByFolder(@RequestParam("bucket") String bucket, @RequestParam("folderPath") String folderPath) {

        return Response.success(minIOFileService.listFilesAndFolders(bucket, folderPath));
    }

    /**
     * 获取一个Bucket 中 某个文件夹下的所有文件列表
     */
    @GetMapping("/getFilesFromFolderByToken")
    public Response<List<FileObject>> listFilesAndFoldersByToken(@RequestParam("folderPath") String folderPath) {
        LoginUser loginUser = RequestContext.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前登陆用户为空");
        }
        String bucketName = loginUser.getUsername();

        // 如果不存在就创建 bucket
        minIOFileService.existBucket(bucketName);

        return Response.success(minIOFileService.listFilesAndFolders(bucketName, folderPath));
    }


    /**
     * 获取一个Bucket 中的所有文件列表
     */
    @GetMapping("/getAllFiles")
    public Response<List<MinioFileInfoVO>> getAllFiles(@RequestParam("bucketName") String bucketName) {
        List<MinioFileInfoVO> res = minIOFileService.getAllFilesByBucketName(bucketName);

        return Response.success(res);
    }

    /**
     * 在指定文件桶， 新建文件
     */
    @PostMapping("/newFile")
    public Response<String> newFile(@RequestParam String bucket, @RequestParam String fileName) throws Exception {
        String filePureName = fileName.split("\\.")[0];
        String fileType = fileName.split("\\.")[1];
        minIOFileService.newFileAndUploadFileToMinio(bucket, filePureName, fileType);

        return Response.success(minIOFileService.getPresignedObjectUrl(bucket, fileName));
    }

    /**
     * 移动文件到指定目录
     */
    @PostMapping("/moveFile")
    public Response<?> moveFile(@RequestBody SystemFIleQto1 qto1) {
        boolean b = minIOFileService.moveFileInMinio(qto1.getBucketName(), qto1.getSourceFilePath(), qto1.getTargetFolderPath());
        if (b) {
            return Response.success();
        } else {
            return Response.error("移动文件失败");
        }
    }

    /**
     * 移动文件夹到指定目录
     */
    @PostMapping("/moveFolder")
    public Response<?> moveFolder(@RequestBody SystemFIleQto1 qto1) {
        boolean b = minIOFileService.transferFolder(qto1.getBucketName(), qto1.getSourceFilePath(), qto1.getTargetFolderPath(), null);
        if (b) {
            return Response.success();
        } else {
            return Response.error("移动文件夹失败");
        }
    }

    /**
     * 新建文件夹
     */
    @PostMapping("/newFolder")
    public Response<String> newFolder(@RequestParam String bucket, @RequestParam String folderName) throws Exception {
        minIOFileService.newFolder(folderName + "/", bucket);
        return Response.success(folderName);
    }

    /**
     * -----------------------------上传文件相关-------------------------------
     */
    @PostMapping("/upload")
    public Response<?> upload(@RequestParam("bucket") String bucket,
                              @RequestParam(value = "path") String path,
                              @RequestParam("file") MultipartFile file,
                              @RequestParam(value = "fileName", required = false) String fileName) {

        String name = file.getOriginalFilename();
        boolean res;
        String newPath = path + name;

        // 如果指定了文件名，则使用指定名称
        if (StringUtils.isNotBlank(fileName)) {
            newPath = path + fileName;
        }

        res = minIOFileService.uploadFile(bucket, file, newPath);
        if (res) {
            return Response.success("上传文件" + name + "到 " + path + " 成功");
        } else {
            return Response.error("上传文件失败");
        }
    }

    /**
     * 上传多文件
     */
    @PostMapping("/uploadMulti")
    public Response<?> uploadToMinio(
            @RequestParam("bucket") String bucket,
            @RequestParam(value = "path", required = false) String path,
            @RequestParam("files") MultipartFile[] files) {

        try {
            List<String> uploadedFiles = new ArrayList<>();

            for (MultipartFile file : files) {
                // 生成唯一文件名
                String originalFilename = file.getOriginalFilename();
                assert originalFilename != null;

                String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
                String pureName = originalFilename.substring(0, originalFilename.lastIndexOf("."));

                String uniqueFileName = pureName + "-" + UUID.randomUUID() + fileExtension;

                // 构建存储路径
                String objectName = (path != null && !path.isEmpty()) ? path + "/" + uniqueFileName : uniqueFileName;

                minIOFileService.uploadFile(bucket, file, objectName);

                uploadedFiles.add(objectName);
            }

            return Response.success("文件上传成功", uploadedFiles);
        } catch (Exception e) {
            return Response.error("文件上传失败: " + e.getMessage());
        }
    }

    /**
     * 上传文件到指定Bucket
     */
    @PostMapping("/uploadToSpecifyBucket")
    public Response<?> uploadToSpecifyBucket(
            @RequestParam("fileName") String fileName,
            @RequestParam("bucketName") String bucketName,
            @RequestParam("file") MultipartFile file) {
        minIOFileService.existBucket(bucketName);
        boolean b = minIOFileService.uploadFile(bucketName, file, fileName);
        if (b) {
            return Response.success("upload " + fileName + " success");
        } else {
            return Response.success("upload " + fileName + " failed");
        }
    }

    /**
     * ******************************* 删除文件、文件夹相关 ***************************
     */
    @PostMapping("/delete")
    public Response<?> delete(@RequestParam("bucket") String bucket,
                              @RequestParam("path") String path) {
        boolean b = minIOFileService.delete(bucket, path);
        if (b) {
            return Response.success();
        } else {
            return Response.error("删除失败");
        }
    }

    /**
     * 删除文件夹
     */
    @PostMapping("/deleteFolder")
    public Response<?> deleteFolder(@RequestParam("bucket") String bucket,
                                    @RequestParam("path") String path) throws Exception {
        minIOFileService.deleteFolder(bucket, path);
        return Response.success();

    }

    /**
     * 批量删除文件
     */
    @PostMapping("/batchDelete")
    public Response<?> batchDelete(@RequestParam("bucket") String bucket, @RequestBody List<String> path) throws Exception {
        boolean b = minIOFileService.batchDelete(bucket, path);
        if (b) {
            return Response.success();
        } else {
            return Response.error("删除失败");
        }

    }


    /**
     * 获取文件外链
     */
    @GetMapping("/url")
    public Response<String> getPresignedObjectUrl(@RequestParam("bucket") String bucket, @RequestParam("fileName") String fileName) {
        return Response.success(minIOFileService.getPresignedObjectUrl(bucket, fileName));
    }

    /**
     * 获取文件外链
     */
    @GetMapping("/fileInfo")
    public Response<String> getFileInfo(@RequestParam("bucket") String bucket, @RequestParam("fileName") String fileName) {
        return Response.success(minIOFileService.getFileContentType(bucket, fileName));
    }


    /**
     * 文件下载
     */
    @GetMapping("/download")
    public void download(@RequestParam("bucket") String bucket, @RequestParam("fileName") String fileName, HttpServletResponse response) {
        try {
            InputStream fileInputStream = minIOFileService.getObject(bucket, fileName);
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            String contextType = minIOFileService.getFileContentType(bucket, fileName);
            response.setContentType(contextType);
            response.setCharacterEncoding("UTF-8");
            IOUtils.copy(fileInputStream, response.getOutputStream());

        } catch (Exception e) {
            log.error("下载失败");
        }
    }

    /**
     * 预览xml 文件内容
     */
    @GetMapping("/preview")
    public void preview(@RequestParam("bucket") String bucket, @RequestParam("fileName") String fileName, HttpServletResponse response) {
        try {
            InputStream fileInputStream = minIOFileService.getObject(bucket, fileName);
            response.setContentType("application/xml"); // 非 attachment
            response.setCharacterEncoding("UTF-8");

            String contextType = minIOFileService.getFileContentType(bucket, fileName);
            response.setContentType(contextType);
            response.setCharacterEncoding("UTF-8");
            IOUtils.copy(fileInputStream, response.getOutputStream());

        } catch (Exception e) {
            log.error("下载失败");
        }
    }

    /**
     * 获取纯文本文件内容
     */
    @GetMapping("/getText")
    public Response<String> getText(@RequestParam("bucket") String bucket, @RequestParam String fileName) throws Exception {

        String res = minIOFileService.readTextFile(bucket, fileName);

        return Response.success(res);
    }

    /**
     * 重命名文件
     */
    @PostMapping("/renameFile")
    public Response<?> renameFile(
            @RequestParam("bucket") String bucket,
            @RequestParam("oldName") String oldName,
            @RequestParam("newName") String newName) {
        try {
            minIOFileService.renameFile(bucket, oldName, newName);
            return Response.success("文件重命名成功");
        } catch (Exception e) {
            return Response.error("文件重命名失败: " + e.getMessage());
        }
    }

    /**
     * 重命名文件夹
     */
    @PostMapping("/renameFolder")
    public Response<?> renameFolder(
            @RequestParam("bucket") String bucket,
            @RequestParam String oldPath,
            @RequestParam String newPath) {
        try {
            minIOFileService.renameFolder(bucket, oldPath, newPath);
            return Response.success("文件夹重命名成功");
        } catch (Exception e) {
            return Response.error("文件夹重命名失败: " + e.getMessage());
        }
    }

    /**
     * 通过URL上传文件到MinIO
     */
    @PostMapping("/upload-from-url")
    public Response<?> uploadFromUrl(@RequestBody FileUrlDTO request) {
        String fileUrl = request.getUrl();
        String objectName = request.getObjectName();
        String bucket = request.getBucket();

        if (fileUrl == null || fileUrl.isEmpty()) {
            return Response.error("文件URL不能为空");
        }

        try {
            UploadResult result = minIOFileService.uploadToMinioFromUrl(bucket, fileUrl, objectName);

            return Response.success(result);

        } catch (IOException e) {
            return Response.error("文件下载失败: " + e.getMessage());
        } catch (Exception e) {
            return Response.error("MinIO上传失败: " + e.getMessage());
        }
    }

    /**
     * 检查文件（秒传）
     */
    @PostMapping("/check")
    public Response<CheckFileResult> checkFile(@RequestBody UploadChunkRequest request) throws Exception {
        CheckFileResult result = minioFileUploadService.checkFile(
                request.getBucketName(),
                request.getFileMd5(),
                request.getPath(),
                request.getFileName(),
                request.getFileSize()
        );
        return Response.success(result);
    }

    /**
     * 上传分片
     */
    @PostMapping("/upload/chunk")
    public Response<Map<String, Object>> uploadChunk(
            @RequestParam("bucketName") String bucketName,
            @RequestParam("file") MultipartFile file,
            @RequestParam("fileMd5") String fileMd5,
            @RequestParam("chunkNumber") Integer chunkNumber,
            @RequestParam("totalChunks") Integer totalChunks) {

        boolean success = minioFileUploadService.uploadChunk(bucketName, file, fileMd5, chunkNumber);
        Map<String, Object> result = new HashMap<>();
        result.put("success", success);
        result.put("chunkNumber", chunkNumber);

        return Response.success(result);
    }

    /**
     * 合并分片
     */
    @PostMapping("/merge")
    public Response<Map<String, Object>> mergeChunks(@Valid @RequestBody MergeChunksRequest request) {
        try {
            String fileUrl = minioFileUploadService.mergeChunks(
                    request.getBucketName(),
                    request.getFileMd5(),
                    request.getPath(),
                    request.getFileName(),
                    request.getTotalChunks()
            );

            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("url", fileUrl);

            return Response.success(result);
        } catch (Exception e) {
            return Response.error(e.getMessage());
        }
    }

    /**
     * 清理未完成的上传
     */
    @DeleteMapping("/cleanup/{bucketName}/{fileMd5}")
    public Response<Map<String, Object>> cleanupIncompleteUploads(@PathVariable String bucketName,
                                                                  @PathVariable String fileMd5) {
        minioFileUploadService.cleanupIncompleteUploads(bucketName, fileMd5);

        Map<String, Object> result = new HashMap<>();
        result.put("success", true);
        result.put("message", "清理完成");

        return Response.success(result);
    }
}